/*-------------------------------------------------------------------------
 *
 * postgres_fdw.h
 *		  远程 PostgreSQL 服务器的外部数据包装器
 *
 * Portions Copyright (c) 2012-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *		  contrib/postgres_fdw/postgres_fdw.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef POSTGRES_FDW_H
#define POSTGRES_FDW_H

#include "foreign/foreign.h"
#include "lib/stringinfo.h"
#include "libpq-fe.h"
#include "nodes/execnodes.h"
#include "nodes/pathnodes.h"
#include "utils/relcache.h"

/*
 * FDW特定的规划器信息保存在RelOptInfo.fdw_private中，用于
 * postgres_fdw外部表。对于baserel，这个结构体是由
 * postgresGetForeignRelSize创建的，尽管一些字段会在以后填充。
 * postgresGetForeignJoinPaths为joinrel创建它， 
 * postgresGetForeignUpperPaths为upperrel创建它。
 */
typedef struct PgFdwRelationInfo
{
	/*
	 * True表示关系可以下推。简单的外部扫描总是为真。
	 */
	bool		pushdown_safe;

	/*
	 * 限制子句，分为安全和不安全的下推子集。
	 * 这些列表中的所有条目都应具有RestrictInfo包装；这
	 * 提高了选择性和成本估计的效率。
	 */
	List	   *remote_conds;
	List	   *local_conds;

	/* 实际的远程限制子句用于扫描（不包括RestrictInfos） */
	List	   *final_remote_exprs;

	/* 我们需要从远程服务器获取的属性编号位图。 */
	Bitmapset  *attrs_used;

	/* True表示query_pathkeys可以安全下推 */
	bool		qp_is_pushdown_safe;

	/* local_conds的成本和选择性。 */
	QualCost	local_conds_cost;
	Selectivity local_conds_sel;

	/* 连接条件的选择性 */
	Selectivity joinclause_sel;

	/* 用于扫描、连接或分组/聚合的估计大小和成本。 */
	double		rows;
	int			width;
	Cost		startup_cost;
	Cost		total_cost;

	/*
	 * 从外部服务器提取的估计行数，以及
	 * 排除从外部服务器传输这些行的成本。
	 * 这些仅在estimate_path_cost_size()中使用。
	 */
	double		retrieved_rows;
	Cost		rel_startup_cost;
	Cost		rel_total_cost;

	/* 从目录中提取的选项。 */
	bool		use_remote_estimate;
	Cost		fdw_startup_cost;
	Cost		fdw_tuple_cost;
	List	   *shippable_extensions;	/* 可移植扩展的OID */
	bool		async_capable;

	/* 缓存的目录信息。 */
	ForeignTable *table;
	ForeignServer *server;
	UserMapping *user;			/* 仅在use_remote_estimate模式下设置 */

	int			fetch_size;		/* 此远程表的提取大小 */

	/*
	 * 关系的名称，用于在EXPLAIN ForeignScan时使用。
	 * 它用于连接和上层关系，但为所有关系设置。
	 * 对于基关系，这实际上只是RT索引作为字符串；
	 * 我们在生成EXPLAIN输出时转换它。
	 * 对于连接和上层关系，该名称指示包含哪些基外部表
	 * 以及使用的连接类型或聚合类型。
	 */
	char	   *relation_name;

	/* 连接信息 */
	RelOptInfo *outerrel;
	RelOptInfo *innerrel;
	JoinType	jointype;
	/* joinclauses仅包含外连接的JOIN/ON条件 */
	List	   *joinclauses;	/* RestrictInfo列表 */

	/* 上层关系信息 */
	UpperRelationKind stage;

	/* 分组信息 */
	List	   *grouped_tlist;

	/* 子查询信息 */
	bool		make_outerrel_subquery; /* 我们是否将outerrel解析为
										 * 子查询？ */
	bool		make_innerrel_subquery; /* 我们是否将innerrel解析为
										 * 子查询？ */
	Relids		lower_subquery_rels;	/* 出现在下层
										 * 子查询中的所有relids */

	/*
	 * 关系的索引。它用于创建表示该关系的子查询的别名。
	 */
	int			relation_index;
} PgFdwRelationInfo;

/*
 * 与连接相关的额外控制信息。
 */
typedef struct PgFdwConnState
{
	AsyncRequest *pendingAreq;	/* 待处理的异步请求 */
} PgFdwConnState;

/* 在postgres_fdw.c中 */
extern int	set_transmission_modes(void);
extern void reset_transmission_modes(int nestlevel);
extern void process_pending_request(AsyncRequest *areq);

/* 在connection.c中 */
extern PGconn *GetConnection(UserMapping *user, bool will_prep_stmt,
							 PgFdwConnState **state);
extern void ReleaseConnection(PGconn *conn);
extern unsigned int GetCursorNumber(PGconn *conn);
extern unsigned int GetPrepStmtNumber(PGconn *conn);
extern void do_sql_command(PGconn *conn, const char *sql);
extern PGresult *pgfdw_get_result(PGconn *conn, const char *query);
extern PGresult *pgfdw_exec_query(PGconn *conn, const char *query,
								  PgFdwConnState *state);
extern void pgfdw_report_error(int elevel, PGresult *res, PGconn *conn,
							   bool clear, const char *sql);

/* 在option.c中 */
extern int	ExtractConnectionOptions(List *defelems,
									 const char **keywords,
									 const char **values);
extern List *ExtractExtensionList(const char *extensionsString,
								  bool warnOnMissing);
extern char *process_pgfdw_appname(const char *appname);
extern char *pgfdw_application_name;

/* 在deparse.c中 */
extern void classifyConditions(PlannerInfo *root,
							   RelOptInfo *baserel,
							   List *input_conds,
							   List **remote_conds,
							   List **local_conds);
extern bool is_foreign_expr(PlannerInfo *root,
							RelOptInfo *baserel,
							Expr *expr);
extern bool is_foreign_param(PlannerInfo *root,
							 RelOptInfo *baserel,
							 Expr *expr);
extern bool is_foreign_pathkey(PlannerInfo *root,
							   RelOptInfo *baserel,
							   PathKey *pathkey);
extern void deparseInsertSql(StringInfo buf, RangeTblEntry *rte,
							 Index rtindex, Relation rel,
							 List *targetAttrs, bool doNothing,
							 List *withCheckOptionList, List *returningList,
							 List **retrieved_attrs, int *values_end_len);
extern void rebuildInsertSql(StringInfo buf, Relation rel,
							 char *orig_query, List *target_attrs,
							 int values_end_len, int num_params,
							 int num_rows);
extern void deparseUpdateSql(StringInfo buf, RangeTblEntry *rte,
							 Index rtindex, Relation rel,
							 List *targetAttrs,
							 List *withCheckOptionList, List *returningList,
							 List **retrieved_attrs);
extern void deparseDirectUpdateSql(StringInfo buf, PlannerInfo *root,
								   Index rtindex, Relation rel,
								   RelOptInfo *foreignrel,
								   List *targetlist,
								   List *targetAttrs,
								   List *remote_conds,
								   List **params_list,
								   List *returningList,
								   List **retrieved_attrs);
extern void deparseDeleteSql(StringInfo buf, RangeTblEntry *rte,
							 Index rtindex, Relation rel,
							 List *returningList,
							 List **retrieved_attrs);
extern void deparseDirectDeleteSql(StringInfo buf, PlannerInfo *root,
								   Index rtindex, Relation rel,
								   RelOptInfo *foreignrel,
								   List *remote_conds,
								   List **params_list,
								   List *returningList,
								   List **retrieved_attrs);
extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
extern void deparseAnalyzeSql(StringInfo buf, Relation rel,
							  List **retrieved_attrs);
extern void deparseTruncateSql(StringInfo buf,
							   List *rels,
							   DropBehavior behavior,
							   bool restart_seqs);
extern void deparseStringLiteral(StringInfo buf, const char *val);
extern EquivalenceMember *find_em_for_rel(PlannerInfo *root,
										  EquivalenceClass *ec,
										  RelOptInfo *rel);
extern EquivalenceMember *find_em_for_rel_target(PlannerInfo *root,
												 EquivalenceClass *ec,
												 RelOptInfo *rel);
extern List *build_tlist_to_deparse(RelOptInfo *foreignrel);
extern void deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root,
									RelOptInfo *foreignrel, List *tlist,
									List *remote_conds, List *pathkeys,
									bool has_final_sort, bool has_limit,
									bool is_subquery,
									List **retrieved_attrs, List **params_list);
extern const char *get_jointype_name(JoinType jointype);

/* 在shippable.c中 */
extern bool is_builtin(Oid objectId);
extern bool is_shippable(Oid objectId, Oid classId, PgFdwRelationInfo *fpinfo);

#endif							/* POSTGRES_FDW_H */
